package com.zliuyno.io.testreactor.netty;


import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.*;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;
import org.junit.Test;

import java.net.InetSocketAddress;

/**
 * @author liuyno
 * @date 2020/11/29 - 22:06
 */
public class MyNetty {

    /**
     * Channel ByteBuffer selector
     * ByteBuffer -- ByteBuf[pool]
     */
    @Test
    public void myByteBuffer() {
//        ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(8, 20);
        //pool
//        ByteBuf buf = UnpooledByteBufAllocator.DEFAULT.heapBuffer(8, 20);
        ByteBuf buf = PooledByteBufAllocator.DEFAULT.heapBuffer(8, 20);

        print(buf);


        buf.writeBytes(new byte[]{1, 2, 3, 4});
        print(buf);
        buf.writeBytes(new byte[]{1, 2, 3, 4});
        print(buf);
        buf.writeBytes(new byte[]{1, 2, 3, 4});
        print(buf);
        buf.writeBytes(new byte[]{1, 2, 3, 4});
        print(buf);
        buf.writeBytes(new byte[]{1, 2, 3, 4});
        print(buf);

        buf.writeBytes(new byte[]{1, 2, 3, 4});
        print(buf);

    }

    public static void print(ByteBuf buf) {
        System.out.println("buf.isReadable() :" + buf.isReadable());
        System.out.println("buf.readerIndex() :" + buf.readerIndex());
        System.out.println("buf.readableBytes() :" + buf.readableBytes());

        System.out.println("buf.isWritable() :" + buf.isWritable());
        System.out.println("buf.writerIndex() :" + buf.writerIndex());
        System.out.println("buf.writableBytes() :" + buf.writableBytes());

        System.out.println("buf.capacity() :" + buf.capacity());
        System.out.println("buf.maxCapacity() :" + buf.maxCapacity());

        System.out.println("buf.isDirect() :" + buf.isDirect());
        System.out.println("-------------------------");
    }


    /**
     * 客户端
     * 连接别人
     * 1.主动发送数据
     * 2.别人什么时候给我发?      基于event selector
     */
    @Test
    public void loopExecutor() throws Exception {
        NioEventLoopGroup selector = new NioEventLoopGroup(2);
        selector.execute(() -> {

            try {
                for (; ; ) {
                    System.out.println("Hello World001");
                    Thread.sleep(1000);
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        selector.execute(() -> {

            try {
                for (; ; ) {
                    System.out.println("Hello World002");
                    Thread.sleep(1000);
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.in.read();
    }


    @Test
    public void clientMode() throws Exception {
        NioEventLoopGroup thread = new NioEventLoopGroup(1);

        //客户端模式
        NioSocketChannel client = new NioSocketChannel();
        thread.register(client);

        //响应式：
        ChannelPipeline p = client.pipeline();
        p.addLast(new MyInHandler());

        ChannelFuture connect = client.connect(new InetSocketAddress("10.7.19.224", 9090));
        ChannelFuture sync = connect.sync();

        ByteBuf byteBuf = Unpooled.copiedBuffer("hello server".getBytes());
        ChannelFuture send = client.writeAndFlush(byteBuf);
        send.sync();

        sync.channel().closeFuture().sync();
        System.out.println("client over.....");


    }

    @Test
    public void nettyClient() throws InterruptedException {
        NioEventLoopGroup g = new NioEventLoopGroup(1);
        Bootstrap bootstrap = new Bootstrap();
        ChannelFuture connect = bootstrap.group(g)
                .channel(NioSocketChannel.class)
//                .handler(new ChannelInit())
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new MyInHandler());
                    }
                })
                .connect(new InetSocketAddress("10.7.19.224", 9090));
        Channel client = connect.sync().channel();
        ByteBuf byteBuf = Unpooled.copiedBuffer("hello server".getBytes());
        ChannelFuture send = client.writeAndFlush(byteBuf);
        send.sync();

        client.closeFuture().sync();
    }

    @Test
    public void serverMode() throws Exception{

        NioEventLoopGroup thread = new NioEventLoopGroup(1);
        NioServerSocketChannel server = new NioServerSocketChannel();

        thread.register(server);
        ChannelPipeline pipeline = server.pipeline();
        pipeline.addLast(new MyAcceptHandler(thread, new ChannelInit()));    //接收客户端并注册到selector
        ChannelFuture bind = server.bind(new InetSocketAddress("10.127.4.227", 9090));
        bind.sync().channel().closeFuture().sync();
        System.out.println("server close .......");

    }


    @Test
    public void nettyServer() throws InterruptedException {
        NioEventLoopGroup g = new NioEventLoopGroup(1);

        ServerBootstrap bs = new ServerBootstrap();
        ChannelFuture bind = bs.group(g, g)
                .channel(NioServerSocketChannel.class)
//                .childHandler(new ChannelInit())
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        ChannelPipeline pipeline = nioSocketChannel.pipeline();
                        pipeline.addLast(new MyInHandler());
                    }
                })
                .bind(new InetSocketAddress("10.127.4.227", 9090));

        bind.sync().channel().closeFuture().sync();


    }

}

class MyAcceptHandler extends ChannelInboundHandlerAdapter {

    private final NioEventLoopGroup selector;
    private final ChannelInboundHandler handler;

    public MyAcceptHandler(NioEventLoopGroup selector, ChannelInboundHandler handler) {
        this.selector = selector;
        this.handler = handler;
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("server register.......");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        SocketChannel client = (SocketChannel) msg;     //accept 我怎么没调

        //2.响应式的 handler
        ChannelPipeline pipeline = client.pipeline();
        pipeline.addLast(handler);
        //1.注册
        selector.register(client);

    }
}

@ChannelHandler.Sharable
class MyInHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client register.......");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client active...");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
//        CharSequence str = buf.readCharSequence(buf.readableBytes(), CharsetUtil.UTF_8);
        CharSequence str = buf.getCharSequence(0, buf.readableBytes(), CharsetUtil.UTF_8);
        System.out.println(str);

        System.out.println();
        ctx.writeAndFlush(buf);
    }
}

@ChannelHandler.Sharable
class ChannelInit extends ChannelInboundHandlerAdapter{

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        Channel client = ctx.channel();
        ChannelPipeline p = client.pipeline();
        p.addLast(new MyInHandler());
//        ctx.pipeline().remove(this);
    }

    /*@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("哈哈 移除我吗？");
        super.channelRead(ctx, msg);
    }*/
}



